/**
 * @项目名称 longlonggo-sample
 * @文件名称 ClassLoadTest.java  版本号：1.0
 * @创建日期 2018年9月27日 
 * @创建作者 me@longlonggo.com
 */
package classload;

import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;

/**
 * 说明： jvm类加载器
 * 
 * @version 1.0
 * @author me@longlonggo.com
 *
 */
public class ClassLoadTest2 {

    public static void main(String[] args) throws IOException {
        // JVM(java虚拟机)启动时，会形成三个层级的加载器加载结构：
        // bootstrap classloader(原始加载器) > extension classloader(扩展类加载器) > system
        // classloader系统（也称为应用）类加载器
        
        // 每个ClassLoader加载class的过程是：
        // 1、检测此Class是否载入过(即在cache中是否有此Class)，如果有到8，如果没有则到2
        // 2、如果parent ClassLoader不存在(没有parent 则一定是引导类加载器(bootstrap classLoader))，到4
        // 3、请求parent classloader类加载器载入，如果成功则到8，不成功则到5
        // 4、请求jvm从bootstrap classloader中载入，如果成功则到8
        // 5、寻找Class文件(从与此classloader相关的路径中寻找)，如果找不到则到7
        // 6、从文件中载入Class，到8
        // 7、抛出ClassNotFoundException
        // 8、返回Class

        /******************************* 【1】系统类加载器 *******************************/
        ClassLoader systemLoader = ClassLoader.getSystemClassLoader();
        // 系统加载器对象：sun.misc.Launcher$AppClassLoader@18b4aac2
        System.out.println("系统加载器：" + systemLoader);
        // 系统加载器加载路径,程序运行的物理路径
        Enumeration<URL> eml = systemLoader.getResources("");
        while (eml.hasMoreElements()) {
            System.out.println("系统加载器路径：" + eml.nextElement());
        }

        
        /******************************* 【2】扩展类加载器 *******************************/
        // 获取 系统类加载器的父加载器，即扩展类加载器对象
        ClassLoader parentLoader = systemLoader.getParent();
        // 扩展类加载器对象：sun.misc.Launcher$ExtClassLoader@5fd0d5ae
        System.out.println("扩展类加载器对象：" + parentLoader);
        System.out.println("扩展类加载器路径：" + System.getProperty("java.ext.dirs"));

        
        /******************************* 【3】引导类加载器 *******************************/
        // 负责加载java的核心类，它实际上不是 java.lang.ClassLoader的子类，而是由JVM自身实现的
        ClassLoader parent2Loader = parentLoader.getParent();
        System.out.println("原始加载器对象：" + parent2Loader);
        URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();
        for (int i = 0; i < urls.length; i++) {
            System.out.println("原始加载器核心类库：" + urls[i].toExternalForm());
        }
        
        // 内容输出如下：
        // 系统加载器：sun.misc.Launcher$AppClassLoader@2a139a55
        // 系统加载器路径：file:/C:/workspace/longlonggo-sample/target/classes/
        
        // 扩展类加载器对象：sun.misc.Launcher$ExtClassLoader@5fd0d5ae
        // 扩展类加载器路径：C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext;C:\Windows\Sun\Java\lib\ext
        
        // 原始加载器对象：null
        // 原始加载器核心类库：file:/C:/Program%20Files/Java/jdk1.8.0_181/jre/lib/resources.jar
        // 原始加载器核心类库：file:/C:/Program%20Files/Java/jdk1.8.0_181/jre/lib/rt.jar
        // 原始加载器核心类库：file:/C:/Program%20Files/Java/jdk1.8.0_181/jre/lib/sunrsasign.jar
        // 原始加载器核心类库：file:/C:/Program%20Files/Java/jdk1.8.0_181/jre/lib/jsse.jar
        // 原始加载器核心类库：file:/C:/Program%20Files/Java/jdk1.8.0_181/jre/lib/jce.jar
        // 原始加载器核心类库：file:/C:/Program%20Files/Java/jdk1.8.0_181/jre/lib/charsets.jar
        // 原始加载器核心类库：file:/C:/Program%20Files/Java/jdk1.8.0_181/jre/lib/jfr.jar
        // 原始加载器核心类库：file:/C:/Program%20Files/Java/jdk1.8.0_181/jre/classes
    }
}
